package com.gitee.wsl.struct.generator.segment

import androidx.lifecycle.Lifecycle
import kotlin.concurrent.Volatile


/**
 * 特别声明: 此算法来自美团的leaf号段模式
 * see： https://github.com/Meituan-Dianping/Leaf/blob/master/leaf-server/src/main/java/com/sankuai/inf/leaf/server/service/SegmentService.java
 *
 * @author opensnail
 * @date 2023-05-04
 * @since 1.2.0
 */
//@Component
//@Slf4j
//@Deprecated("")
//class SegmentIdGenerator : IdGenerator, Lifecycle {
//    private val service = ThreadPoolExecutor(
//        5, 10, 60L, TimeUnit.SECONDS,
//        LinkedBlockingDeque<E>(5000), UpdateThreadFactory()
//    )
//
//    @Volatile
//    private var initOK = false
//    private val cache: MutableMap<Pair<String, String>, SegmentBuffer> = ConcurrentHashMap()
//
//    @Autowired
//    private val sequenceAllocMapper: SequenceAllocMapper? = null
//
//    override fun start() {
//        SnailJobLog.LOCAL.info("SegmentIdGenerator start")
//        // 确保加载到kv后才初始化成功
//        updateCacheFromDb()
//        initOK = true
//        updateCacheFromDbAtEveryMinute()
//        SnailJobLog.LOCAL.info("SegmentIdGenerator start end")
//    }
//
//    override fun close() {
//        SnailJobLog.LOCAL.info("SegmentIdGenerator close")
//    }
//
//    private fun updateCacheFromDbAtEveryMinute() {
//        val service = Executors.newSingleThreadScheduledExecutor { r: Runnable? ->
//            val t = Thread(r)
//            t.name = "check-id-cache-thread"
//            t.isDaemon = true
//            t
//        }
//        service.scheduleWithFixedDelay({ this.updateCacheFromDb() }, 60, 60, TimeUnit.SECONDS)
//    }
//
//    private fun updateCacheFromDb() {
//        try {
//            val sequenceAllocs: List<SequenceAlloc> = sequenceAllocMapper
//                .selectList(
//                    LambdaQueryWrapper<SequenceAlloc>()
//                        .select(SequenceAlloc::getGroupName, SequenceAlloc::getNamespaceId)
//                )
//            if (CollUtil.isEmpty(sequenceAllocs)) {
//                return
//            }
//
//            val dbTags: List<Pair<String, String>> = StreamUtils.toList(
//                sequenceAllocs
//            ) { sequenceAlloc ->
//                Pair.of(
//                    sequenceAlloc.getGroupName(),
//                    sequenceAlloc.getNamespaceId()
//                )
//            }
//
//            val cacheTags: List<Pair<String, String>> = ArrayList(cache.keys)
//            val insertTagsSet: MutableSet<Pair<String, String>> = HashSet(dbTags)
//            val removeTagsSet: MutableSet<Pair<String, String>> = HashSet(cacheTags)
//            //db中新加的tags灌进cache
//            for (i in cacheTags.indices) {
//                val tmp = cacheTags[i]
//                insertTagsSet.remove(tmp)
//            }
//            for (tag in insertTagsSet) {
//                val buffer = SegmentBuffer()
//                buffer.key = tag
//                val segment = buffer.current
//                segment.value = AtomicLong(0)
//                segment.max = 0
//                segment.step = 0
//                cache[tag] = buffer
//                SnailJobLog.LOCAL.debug(
//                    "Add tag {} from db to IdCache, SegmentBuffer {}",
//                    tag,
//                    buffer
//                )
//            }
//            //cache中已失效的tags从cache删除
//            for (i in dbTags.indices) {
//                val tmp = dbTags[i]
//                removeTagsSet.remove(tmp)
//            }
//            for (tag in removeTagsSet) {
//                cache.remove(tag)
//                SnailJobLog.LOCAL.debug("Remove tag {} from IdCache", tag)
//            }
//        } catch (e: Exception) {
//            SnailJobLog.LOCAL.error("update cache from db exception", e)
//        }
//    }
//
//    fun get(groupName: String?, namespaceId: String?): String {
//        if (!initOK) {
//            return EXCEPTION_ID_IDCACHE_INIT_FALSE.toString()
//        }
//
//        val key: Pair<String, String> = Pair.of(groupName, namespaceId)
//        if (cache.containsKey(key)) {
//            val buffer = cache[key]
//            if (!buffer!!.isInitOk) {
//                synchronized(buffer) {
//                    if (!buffer.isInitOk) {
//                        try {
//                            updateSegmentFromDb(key, buffer.current)
//                            SnailJobLog.LOCAL.debug(
//                                "Init buffer. Update key {} {} from db",
//                                key,
//                                buffer.current
//                            )
//                            buffer.isInitOk = true
//                        } catch (e: Exception) {
//                            SnailJobLog.LOCAL.error("Init buffer {} exception", buffer.current, e)
//                        }
//                    }
//                }
//            }
//            return getIdFromSegmentBuffer(cache[key]!!)
//        }
//        return EXCEPTION_ID_KEY_NOT_EXISTS.toString()
//    }
//
//    fun updateSegmentFromDb(key: Pair<String?, String?>, segment: Segment) {
//        val buffer = segment.buffer
//        val sequenceAlloc: SequenceAlloc
//        val wrapper: LambdaUpdateWrapper<SequenceAlloc> = LambdaUpdateWrapper<SequenceAlloc>()
//            .setSql("max_id = max_id + step")
//            .set(SequenceAlloc::getUpdateDt, Date())
//            .eq(SequenceAlloc::getGroupName, key.getKey())
//            .eq(SequenceAlloc::getNamespaceId, key.getValue())
//        if (!buffer.isInitOk) {
//            sequenceAllocMapper.update(wrapper)
//            sequenceAlloc = sequenceAllocMapper.selectOne(
//                LambdaQueryWrapper<SequenceAlloc>()
//                    .eq(SequenceAlloc::getGroupName, key.getKey())
//                    .eq(SequenceAlloc::getNamespaceId, key.getValue())
//            )
//            buffer.step = sequenceAlloc.getStep()
//            buffer.minStep = sequenceAlloc.getStep() //leafAlloc中的step为DB中的step
//        } else if (buffer.updateTimestamp == 0L) {
//            sequenceAllocMapper.update(wrapper)
//            sequenceAlloc = sequenceAllocMapper.selectOne(
//                LambdaQueryWrapper<SequenceAlloc>()
//                    .eq(SequenceAlloc::getGroupName, key.getKey())
//                    .eq(SequenceAlloc::getNamespaceId, key.getValue())
//            )
//            buffer.updateTimestamp = System.currentTimeMillis()
//            buffer.step = sequenceAlloc.getStep()
//            buffer.minStep = sequenceAlloc.getStep() //leafAlloc中的step为DB中的step
//        } else {
//            val duration = System.currentTimeMillis() - buffer.updateTimestamp
//            var nextStep = buffer.step
//            if (duration < SEGMENT_DURATION) {
//                if (nextStep * 2 > MAX_STEP) {
//                    //do nothing
//                } else {
//                    nextStep = nextStep * 2
//                }
//            } else if (duration < SEGMENT_DURATION * 2) {
//                //do nothing with nextStep
//            } else {
//                nextStep = if (nextStep / 2 >= buffer.minStep) nextStep / 2 else nextStep
//            }
//            SnailJobLog.LOCAL.debug(
//                "leafKey[{}], step[{}], duration[{}mins], nextStep[{}]",
//                key,
//                buffer.step,
//                String.format("%.2f", (duration.toDouble() / (1000 * 60))),
//                nextStep
//            )
//            val wrapper1: LambdaUpdateWrapper<SequenceAlloc> = LambdaUpdateWrapper<SequenceAlloc>()
//                .setSql("max_id = max_id + $nextStep")
//                .set(SequenceAlloc::getUpdateDt, Date())
//                .eq(SequenceAlloc::getGroupName, key.getKey())
//                .eq(SequenceAlloc::getNamespaceId, key.getValue())
//            sequenceAllocMapper.update(wrapper1)
//            sequenceAlloc = sequenceAllocMapper.selectOne(
//                LambdaQueryWrapper<SequenceAlloc>()
//                    .eq(SequenceAlloc::getGroupName, key.getKey())
//                    .eq(SequenceAlloc::getNamespaceId, key.getValue())
//            )
//            buffer.updateTimestamp = System.currentTimeMillis()
//            buffer.step = nextStep
//            buffer.minStep = sequenceAlloc.getStep() //leafAlloc的step为DB中的step
//        }
//        // must set value before set max
//        val value: Long = sequenceAlloc.getMaxId() - buffer.step
//        segment.value.set(value)
//        segment.max = sequenceAlloc.getMaxId()
//        segment.step = buffer.step
//    }
//
//    fun getIdFromSegmentBuffer(buffer: SegmentBuffer): String {
//        while (true) {
//            buffer.rLock().lock()
//            try {
//                val segment = buffer.current
//                if (!buffer.isNextReady && (segment.idle < 0.9 * segment.step) && buffer.threadRunning.compareAndSet(
//                        false,
//                        true
//                    )
//                ) {
//                    service.execute {
//                        val next = buffer.segments[buffer.nextPos()]
//                        var updateOk = false
//                        try {
//                            updateSegmentFromDb(buffer.key!!, next)
//                            updateOk = true
//                            SnailJobLog.LOCAL.debug(
//                                "update segment {} from db {}",
//                                buffer.key,
//                                next
//                            )
//                        } catch (e: Exception) {
//                            SnailJobLog.LOCAL.warn(
//                                buffer.key.toString() + " updateSegmentFromDb exception",
//                                e
//                            )
//                        } finally {
//                            if (updateOk) {
//                                buffer.wLock().lock()
//                                buffer.isNextReady = true
//                                buffer.threadRunning.set(false)
//                                buffer.wLock().unlock()
//                            } else {
//                                buffer.threadRunning.set(false)
//                            }
//                        }
//                    }
//                }
//                val value = segment.value.getAndIncrement()
//                if (value < segment.max) {
//                    return value.toString()
//                }
//            } finally {
//                buffer.rLock().unlock()
//            }
//            waitAndSleep(buffer)
//            buffer.wLock().lock()
//            try {
//                val segment = buffer.current
//                val value = segment.value.getAndIncrement()
//                if (value < segment.max) {
//                    return value.toString()
//                }
//                if (buffer.isNextReady) {
//                    buffer.switchPos()
//                    buffer.isNextReady = false
//                } else {
//                    SnailJobLog.LOCAL.error("Both two segments in {} are not ready!", buffer)
//                    return EXCEPTION_ID_TWO_SEGMENTS_ARE_NULL.toString()
//                }
//            } finally {
//                buffer.wLock().unlock()
//            }
//        }
//    }
//
//    private fun waitAndSleep(buffer: SegmentBuffer) {
//        var roll = 0
//        while (buffer.threadRunning.get()) {
//            roll += 1
//            if (roll > 10000) {
//                try {
//                    TimeUnit.MILLISECONDS.sleep(20)
//                    break
//                } catch (e: InterruptedException) {
//                    SnailJobLog.LOCAL.warn("Thread {} Interrupted", Thread.currentThread().name)
//                    break
//                }
//            }
//        }
//    }
//
//    override fun supports(mode: Int): Boolean {
//        return IdGeneratorModeEnum.SEGMENT.getMode() === mode
//    }
//
//    override fun idGenerator(groupName: String?, namespaceId: String): String {
//        val time: String =
//            DateUtils.format(DateUtils.toNowLocalDateTime(), DateUtils.PURE_DATETIME_MS_PATTERN)
//        return time + get(groupName, namespaceId)
//    }
//
//    class UpdateThreadFactory : ThreadFactory {
//        override fun newThread(r: Runnable): Thread {
//            return Thread(r, "Thread-Segment-Update-" + nextThreadNum())
//        }
//
//        companion object {
//            private var threadInitNumber = 0
//
//            @Synchronized
//            private fun nextThreadNum(): Int {
//                return threadInitNumber++
//            }
//        }
//    }
//
//    companion object {
//        /**
//         * IDCache未初始化成功时的异常码
//         */
//        private const val EXCEPTION_ID_IDCACHE_INIT_FALSE: Long = -1
//
//        /**
//         * key不存在时的异常码
//         */
//        private const val EXCEPTION_ID_KEY_NOT_EXISTS: Long = -2
//
//        /**
//         * SegmentBuffer中的两个Segment均未从DB中装载时的异常码
//         */
//        private const val EXCEPTION_ID_TWO_SEGMENTS_ARE_NULL: Long = -3
//
//        /**
//         * 最大步长不超过100,0000
//         */
//        private const val MAX_STEP = 1000000
//
//        /**
//         * 一个Segment维持时间为15分钟
//         */
//        private const val SEGMENT_DURATION = 15 * 60 * 1000L
//    }
//}
